import fs from "fs-extra";
import path from "path";
import { simpleGit } from "simple-git";
import { spawn } from "cross-spawn";
import { EslintPluginConfigModel } from "./Model.js";
import { ProjectTypeEnum } from "@/types/plugin-type.js";

export interface TaskResult {
  name: string;
  status: "success" | "failed";
  duration: number;
  error?: string;
}

export class EslintPluginService {
  private currentPath: string;
  private packageJsonPath: string;
  private gitDirPath: string;
  private results: TaskResult[] = [];

  constructor() {
    this.currentPath = process.cwd();
    this.packageJsonPath = path.join(this.currentPath, "package.json");
    this.gitDirPath = path.join(this.currentPath, ".git");
  }

  /**
   * 获取任务执行结果
   */
  getResults(): TaskResult[] {
    return this.results;
  }

  /**
   * 记录任务执行结果
   */
  private recordTaskResult(
    name: string,
    startTime: number,
    status: "success" | "failed",
    error?: string
  ) {
    const duration = Date.now() - startTime;
    this.results.push({ name, status, duration, error });
  }

  /**
   * 验证命令参数
   */
  async validateCommand(taskType: string, projectType: string): Promise<void> {
    const startTime = Date.now();
    try {
      if (taskType !== "eslint") {
        throw new Error("不支持的任务类型，请使用 -t eslint");
      }
      if (
        ![
          ProjectTypeEnum.BROWSER,
          ProjectTypeEnum.NODE,
          ProjectTypeEnum.UNIAPP,
        ].includes(projectType as ProjectTypeEnum)
      ) {
        throw new Error("不支持的项目类型，请使用 -p browser, node, uniapp");
      }
      this.recordTaskResult("命令参数验证", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("命令参数验证", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 验证项目路径
   */
  async validatePath(): Promise<void> {
    const startTime = Date.now();
    try {
      if (
        !fs.existsSync(this.packageJsonPath) ||
        !fs.existsSync(this.gitDirPath)
      ) {
        throw new Error("请在项目根目录下运行此命令");
      }
      this.recordTaskResult("项目路径验证", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("项目路径验证", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 验证工作区状态
   */
  async validateWorkspace(): Promise<void> {
    const startTime = Date.now();
    try {
      const git = simpleGit(this.currentPath);
      const status = await git.status();
      if (
        status.created.length > 0 ||
        status.deleted.length > 0 ||
        status.modified.length > 0 ||
        status.renamed.length > 0 ||
        status.not_added.length > 0
      ) {
        throw new Error("当前仓库有未保存的变更，请先保存");
      }
      this.recordTaskResult("工作区验证", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("工作区验证", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 清理依赖
   */
  async cleanDependencies(): Promise<void> {
    const startTime = Date.now();
    try {
      // 删除 node_modules
      await fs.remove(path.join(this.currentPath, "node_modules"));

      // 删除 package.json 中的 eslint 和 prettier 相关依赖
      const packageJson = await fs.readJson(this.packageJsonPath);
      const dependencyKeys = [
        "dependencies",
        "devDependencies",
        "peerDependencies",
        "optionalDependencies",
      ];
      dependencyKeys.forEach((key) => {
        if (packageJson[key]) {
          const newDependencies = Object.fromEntries(
            Object.entries(packageJson[key]).filter(
              ([depName]) => !/(eslint|prettier)/i.test(depName)
            )
          );
          packageJson[key] = newDependencies;
        }
      });
      await fs.writeJson(this.packageJsonPath, packageJson, { spaces: 2 });

      // 删除 package-lock.json
      await fs.remove(path.join(this.currentPath, "package-lock.json"));
      this.recordTaskResult("清理依赖", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("清理依赖", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 清理配置文件
   */
  async cleanConfigFiles(): Promise<void> {
    const startTime = Date.now();
    try {
      const files = await fs.readdir(this.currentPath);
      const configFilesToDelete = files.filter(
        (file) =>
          /^(eslint|\.eslint)/i.test(file) ||
          /^(prettier|\.prettier)/i.test(file)
      );
      for (const file of configFilesToDelete) {
        await fs.remove(path.join(this.currentPath, file));
      }
      this.recordTaskResult("清理配置文件", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("清理配置文件", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 创建配置文件
   */
  async createConfigFiles(projectType: string): Promise<void> {
    const startTime = Date.now();
    try {
      // 获取配置文件内容
      const eslintContent = await EslintPluginConfigModel.getConfigFileContent(
        "eslint",
        projectType
      );
      const prettierContent =
        await EslintPluginConfigModel.getConfigFileContent("prettier");
      const editorConfigContent =
        await EslintPluginConfigModel.getConfigFileContent("editorconfig");

      // 写入配置文件
      const config = await EslintPluginConfigModel.getConfig();
      await fs.writeFile(
        path.join(this.currentPath, config.configFiles.eslint),
        eslintContent
      );
      await fs.writeFile(
        path.join(this.currentPath, config.configFiles.prettier),
        prettierContent
      );
      await fs.writeFile(
        path.join(this.currentPath, config.configFiles.editorconfig),
        editorConfigContent
      );

      this.recordTaskResult("创建配置文件", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("创建配置文件", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 更新 package.json 脚本
   */
  async updatePackageScripts(): Promise<void> {
    const startTime = Date.now();
    try {
      const packageJson = await fs.readJson(this.packageJsonPath);
      const config = await EslintPluginConfigModel.getConfig();
      packageJson.scripts = {
        ...packageJson.scripts,
        ...config.scripts,
      };
      await fs.writeJson(this.packageJsonPath, packageJson, { spaces: 2 });
      this.recordTaskResult("更新 package.json 脚本", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult(
        "更新 package.json 脚本",
        startTime,
        "failed",
        error.message
      );
      throw error;
    }
  }

  /**
   * 安装依赖
   */
  async installDependencies(): Promise<void> {
    const startTime = Date.now();
    try {
      // 安装 @zmn/eslint-plugin
      await new Promise<void>((resolve, reject) => {
        const installProcess = spawn(
          "npm",
          ["install", "@zmn/eslint-plugin@latest", "-D"],
          { stdio: "ignore" }
        );
        installProcess.on("close", (code) => {
          if (code === 0) {
            resolve();
          } else {
            reject(new Error("@zmn/eslint-plugin 安装失败"));
          }
        });
      });

      // 安装其他依赖
      await new Promise<void>((resolve, reject) => {
        const installProcess = spawn("npm", ["i"], { stdio: "ignore" });
        installProcess.on("close", (code) => {
          if (code === 0) {
            resolve();
          } else {
            reject(new Error("依赖安装失败"));
          }
        });
      });

      this.recordTaskResult("安装依赖", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("安装依赖", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 执行 ESLint 验证
   */
  async runEslintVerification(): Promise<void> {
    const startTime = Date.now();
    try {
      await new Promise<void>((resolve, reject) => {
        const verifyProcess = spawn("npx", ["eslint", "eslint.config.mjs"], {
          stdio: "inherit",
        });
        // const verifyProcess = spawn("npm", ["run", "lint:script"], {
        //   stdio: "inherit",
        // });
        verifyProcess.on("close", (code) => {
          if (code === 0) {
            resolve();
          } else {
            reject(new Error("ESLint 验证失败"));
          }
        });
      });
      this.recordTaskResult("ESLint 验证", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("ESLint 验证", startTime, "failed", error.message);
      throw error;
    }
  }

  /**
   * 提交变更
   */
  async commitChanges(): Promise<void> {
    const startTime = Date.now();
    try {
      const git = simpleGit(this.currentPath);
      await git.add(".");
      await git.commit("升级 eslint 插件，以便统一编码规范");
      this.recordTaskResult("提交变更", startTime, "success");
    } catch (error: any) {
      this.recordTaskResult("提交变更", startTime, "failed", error.message);
      throw error;
    }
  }
}
